package com.matt.service.care.impl;


import com.matt.domain.care.HLCareBaseRecord;
import com.matt.foundation.model.DailyRange;
import com.matt.service.care.HLCareBaseService;
import com.matt.service.care.HLDailyRecordService;
import com.matt.service.care.po.HLCareBaseRecordPO;
import com.starinside.wp.domain.Children;
import com.starinside.wp.foundation.exception.BusinessException;
import com.starinside.wp.foundation.model.ErrorCode;
import com.starinside.wp.service.ChildrenService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Service
public class HLCareBaseServiceImpl<T1 extends HLCareBaseRecord, T2 extends JpaSpecificationExecutor<T1> & JpaRepository<T1,String>, T3 extends HLCareBaseRecordPO>
        implements HLCareBaseService<T1, T3> {

    T2 baseRepository;
    public void setBaseRepository(T2 baseRepository) {
        this.baseRepository = baseRepository;
    }

    @Autowired
    ChildrenService childrenService;

    @Autowired
    HLDailyRecordService dailyRecordService;

    private Children permissionCheck(String areaId, String childId){
        Children c = childrenService.getById(childId);
        if (c == null || !areaId.equals(c.getAreaId())){
            throw new BusinessException(ErrorCode.CHILDREN_NOT_EXIST, "宝贝不存在");
        }
        return c;
    }


    @Override
    public T1 get(String areaId, String staffId, String childId, String id) {
        T1 t = baseRepository.getOne(id);
        if (t == null || !t.getChildId().equals(childId) || t.getDeleted()){
            return null;
        }
        return t;
    }

    @Override
    public Page<T1> page(String areaId, String staffId, String childId, PageRequest pageRequest) {
        Specification<T1> specification = new Specification<T1>() {
            @Override
            public Predicate toPredicate(Root<T1> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                Predicate p1 = criteriaBuilder.and(criteriaBuilder.equal(root.get("childId"), childId), criteriaBuilder.equal(root.get("deleted"), 0));
                query.where(p1);
                return query.getRestriction();
            }
        };

        Page<T1> page = baseRepository.findAll(specification, pageRequest);

        return page;
    }

    @Override
    public List<T1> dailyRecords(String areaId, String staffId, String childId, Date daily){
        if (daily == null){
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "参数错误");
        }

        //计算daily时间
        DailyRange dr = DailyRange.of(daily);

        Specification<T1> specification = new Specification<T1>() {
            @Override
            public Predicate toPredicate(Root<T1> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                Predicate p4 = criteriaBuilder.equal(root.get("childId"), childId);
                Predicate p3 = criteriaBuilder.equal(root.get("deleted"), 0);
                Predicate p2 = criteriaBuilder.between(root.get("eventTime"), dr.getDayBegin(), dr.getDayEnd());
                Predicate p1 = criteriaBuilder.and(p2, p3, p4);

                query.where(p1);

                return query.getRestriction();
            }
        };

        List<T1> dailyRecords = baseRepository.findAll(specification);
        return dailyRecords;
    }

    @Override
    public T1 add(String areaId, String staffId, T3 param) {
        Children c = permissionCheck(areaId, param.getChildId());

        ParameterizedType ptype = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class clazz = (Class<T1>) ptype.getActualTypeArguments()[0];

        try {
            T1 o = null;
            if (StringUtils.isNotBlank(param.getId())){

//                permissionCheck(areaId,param.getChildId());
                o = baseRepository.getOne(param.getId());

                if (!o.getCreatedBy().equals(staffId)){
                    throw new BusinessException(ErrorCode.PERMISSION_DENIED, "");
                }

            }else {
                o = (T1) clazz.newInstance();
            }

            BeanUtils.copyProperties(param, o, "id","childIds");

            o.setChildName(c.getName());
            o.setCreatedBy(staffId);
            o.setAreaId(areaId);
            o.setCreated(new Date());

            baseRepository.save(o);
            baseRepository.flush();

            if (StringUtils.isBlank(param.getId())) {
                dailyRecordService.markCareRecord(staffId, o);
//                dailyRecordService.pushCareRecord(staffId, o); //家长操作不需要推送
            }

            return o;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        throw new BusinessException(ErrorCode.UNDEFINED, "模板对象错误");
    }
}
